package org.dtrd.modules.flup.controller;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.base.BaseController;
import org.dtrd.common.api.vo.Result;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.modules.base.service.BaseCommonService;
import org.dtrd.modules.flup.entity.bean.*;
import org.dtrd.modules.flup.entity.po.DtrdRlFlupProjectRecord;
import org.dtrd.modules.flup.entity.request.FlupStatusUpdateRequest;
import org.dtrd.modules.flup.entity.request.PatientFlup;
import org.dtrd.modules.flup.service.IDtrdEntRdFlupAppointmentRecordService;
import org.dtrd.modules.flup.service.IDtrdEntRdFlupEvaluationService;
import org.dtrd.modules.flup.service.IDtrdRlFlupProjectRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;

import static org.dtrd.common.constant.CommonConstant.*;
import static org.dtrd.config.system.SystemState.ResponseState.*;

/**
 * @author qr
 * @date 2021/12/22 15:11
 */
@Api(tags = "复诊随访记录")
@RestController
@Slf4j
@RequestMapping("/flup/patient/")
public class PatientFlupController extends BaseController {

    @Autowired
    private IDtrdEntRdFlupAppointmentRecordService flupAppointmentRecordService;
    @Autowired
    private BaseCommonService baseCommonService;
    @Autowired
    private IDtrdEntRdFlupEvaluationService flupEvaluationService;
    @Autowired
    private IDtrdRlFlupProjectRecordService flupProjectRecordService;

    @ApiOperation("保存复诊评价内容")
    @PostMapping("evaluation/save")
    public Result<?> saveOrUpdateFlupEvaluation(@RequestBody FlupEvaluation flupEvaluation) {
        boolean result = flupEvaluationService.saveFlupEvaluation(flupEvaluation);
        String logContent = String.format("保存复诊评价内容: %s", flupEvaluation);
        baseCommonService.addLog(logContent, OPERATE_TYPE_QUERY);
        return result ? Result.OK() : error(STATE_OPERATION_FAILURE);
    }

    @ApiOperation(value = "获取患者的复诊记录详情", response = FlupRecordDetail.class)
    @GetMapping("get")
    public Result<?> getFlupRecordDetail(@RequestParam("id") Integer id) {
        if (isIntParamInvalid(id)) {
            return error(STATE_PARAMS_MISSING);
        }
        FlupRecordDetail flupRecord = flupAppointmentRecordService.getFlupRecordDetail(id);
        String logContent = String.format("查询患者的复诊记录详情，查询详情id：%d", id);
        baseCommonService.addLog(logContent, OPERATE_TYPE_QUERY);
        return Result.OK(flupRecord);
    }

    @ApiOperation("获取患者本周的复诊记录")
    @GetMapping("get/week")
    public Result<?> getPatientFlupRecord(@RequestParam("patientId") Integer patientId) {
        if (isIntParamInvalid(patientId)) {
            return error(STATE_PARAMS_MISSING);
        }
        String logContent = String.format("获取患者本周的复诊记录，患者id：%d", patientId);
        baseCommonService.addLog(logContent, OPERATE_TYPE_QUERY);
        return Result.OK();
    }

    private final static Integer PM = 13;

    @ApiOperation("患者预约门诊记录保存")
    @PostMapping("saveOrUpdate")
    public Result<?> savePatientFlup(@RequestBody @Validated PatientFlup info) throws ParseException {
        Integer patientId = info.getPatientId();
        Integer doctorId = info.getDoctorId();
        Integer templateId = info.getTemplateId();
        String flupDateStr = info.getFlupDate();
        Integer flupTime = info.getFlupTime();
        String orgCode = info.getOrgCode();

        // 转换时间类型
        DateTime flupDate = wrapperDate(flupDateStr, flupTime);
        info.setFlupDateDate(flupDate);
        // 查询指定日期指定时段是否有患者预约
        Boolean currentTimeHasFlup = flupAppointmentRecordService.currentTimeHasFlup(doctorId, flupDateStr, flupTime);
        if (currentTimeHasFlup) {
            return Result.error("当前时段已有患者预约");
        }
        // 每个患者一周只能复诊一次
        // 如果本周已经有已完成状态的复诊记录您就不能再约本周了，但是您可以约这周以后的日期
        if (flupAppointmentRecordService.hasPatientFinishedFlupRecordThisWeek(patientId)
                && DateUtils.isNotAfterThisWeek(flupDate)) {
            return Result.error("该患者本周已经完成过一次复诊");
        }
        // 新增记录的时候不能有未完成状态的复诊状态
        // 未完成的复诊状态: 待复诊 / 复诊中 / 已预约
        if (info.getDataId() == null
                && flupAppointmentRecordService.hasPatientUnfinishedFlupRecord(patientId)) {
            return Result.error("该患者有未完成的预约");
        }
        // 周末 / 周五下午 / 过去时间不能预约
        int dayOfWeek = flupDate.getField(DateField.DAY_OF_WEEK);
        int hour = flupDate.getField(DateField.HOUR_OF_DAY);
        log.info("PatientFlupController.savePatientFlup.[info] dayOfWeek=" + dayOfWeek + " ; flupDate.isBefore(new Date())=" + flupDate.isBefore(new Date()) + "； flupDate.compareTo(new Date()))=" + (flupDate.compareTo(new Date()))+"; flupDFate="+flupDate+"; new Date="+(new Date()) + "; hour=" + hour + ";((dayOfWeek == Calendar.FRIDAY && hour >= PM))=" + ((dayOfWeek == Calendar.FRIDAY && hour >= PM)));
        Date date = new Date();
        long stampTime = flupDate.getTime() - date.getTime();
        if (dayOfWeek == Calendar.SUNDAY
                || dayOfWeek == Calendar.SATURDAY
                || (dayOfWeek == Calendar.FRIDAY && hour >= PM)
                ||stampTime <= 0) {
            return Result.error("该时段不能预约");
        }

        // 已复诊状态改成新增
        FlupRecord flupRecordLatest = flupAppointmentRecordService.getPatientFlupRecordLatest(patientId);
        if (flupRecordLatest != null && flupRecordLatest.getFlupStatus().equals(Constant.FlupStatus.HadVisited.getStatus())) {
            info.setDataId(null);
        }
        // 保存记录
        boolean result = flupAppointmentRecordService.savePatientFlup(info);
        // 存系统日志
        String logContent = String.format("患者预约门诊记录保存，预约患者id：%d, 预约医生id: %d, 预约复诊模版: %d, 预约时间: %s", patientId, doctorId, templateId, flupDateStr);
        baseCommonService.addLog(logContent, OPERATE_TYPE_SAVE_OR_UPDATE);
        return result ? Result.OK() : error(STATE_OPERATION_FAILURE);
    }

    @ApiOperation(value = "修改患者的复诊状态", notes = "type=1 : 状态改成复诊中, type=2 状态改成已复诊")
    @PostMapping("status/update")
    public Result<?> updatePatientFlupStatus(@RequestBody FlupStatusUpdateRequest request) {
        Integer flupId = request.getFlupId();
        Integer type = request.getType();
        if (isIntParamInvalid(flupId)) {
            return error(STATE_PARAMS_MISSING);
        }
        boolean result = flupAppointmentRecordService.updatePatientFlupStatus(flupId, type, request.getFlupContent());
        String logContent = String.format("修改患者的复诊状态，复诊记录id：%d, 修改类型id: %d", flupId, type);
        baseCommonService.addLog(logContent, OPERATE_TYPE_UPDATE);
        return result ? Result.OK() : error(STATE_OPERATION_FAILURE);
    }

    @ApiOperation(value = "修改患者的复诊状态", notes = "type=1 : 状态改成复诊中, type=2 状态改成已复诊")
    @PostMapping("content/update")
    public Result<?> updatePatientFlupContent(@RequestBody FlupStatusUpdateRequest request) {
        Integer flupId = request.getFlupId();
        if (isIntParamInvalid(flupId)) {
            return error(STATE_PARAMS_MISSING);
        }
        boolean result = flupAppointmentRecordService.updatePatientFlupContent(flupId, request.getFlupContent());
        String logContent = String.format("修改患者的复诊状态，复诊记录id：%d, 修改内容: %s", flupId, request.getFlupContent());
        baseCommonService.addLog(logContent, OPERATE_TYPE_UPDATE);
        return result ? Result.OK() : error(STATE_OPERATION_FAILURE);
    }

    /**
     * 查 patient 表 -> 查复诊预约表 -> 根据 flupId 和 patientId 生成更改状态接口 -> 生成二维码 -> 存 patient 表的字段
     */
    @ApiOperation(value = "获取患者相关的二维码", notes = "根据type获取不同类型的二维码, type=1: 接待码, type=2: 结束码")
    @GetMapping("/qrcode")
    public Result<?> getPatientQrCode(
            @ApiParam(name = "患者id", required = true, example = "351") @RequestParam Integer patientId,
            @ApiParam(name = "二维码类型, 1:接待码, 2:结束码", required = true, example = "1") @RequestParam Integer type) {
        String qrCode = flupAppointmentRecordService.getPatientFlupQrCode(patientId, type);
        return Result.OK(qrCode);
    }

    @ApiOperation(value = "分页查询患者的复诊记录", response = PatientFlupListInfo.class)
    @GetMapping("page")
    public Result<?> pagePatientFlup(@RequestParam("patientId") Integer patientId,
                                     @RequestParam(value = "date", required = false) String date,
                                     @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
                                     @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize) {
        // 如果有传入查询日期则进行校验， 没有则默认为时间
        Date startDate = null;
        Date endDate = null;
        if (StrUtil.isNotBlank(date)) {
            try {
                startDate = DateUtils.parseDate(date, DateUtils.short_date_sdf_yd.get().toPattern());
                endDate = DateUtils.nextMonth(startDate);
            } catch (ParseException e) {
                e.printStackTrace();
                return error(STATE_PARAMS_ERROR);
            }
        }
        IPage<PatientFlupListInfo> queryPage = flupAppointmentRecordService.pagePatientFlup(patientId, startDate, endDate, page, pageSize);
        String logContent = String.format("分页查询患者的复诊记录，查询患者id：%d, 查询日期: %s", patientId, date);
        baseCommonService.addLog(logContent, OPERATE_TYPE_QUERY);
        return Result.OK(queryPage);
    }


    @ApiOperation("保存复诊项目状态")
    @PostMapping("item/save")
    public Result<?> saveFlupItemStateAndRemark(@RequestBody FlupProjectRecord item) {
        Integer flupProjectId = item.getFlupProjectId();
        if (isIntParamInvalid(flupProjectId)) {
            return error(STATE_PARAMS_MISSING);
        }
        DtrdRlFlupProjectRecord record = flupProjectRecordService.getById(flupProjectId);
        if (record == null) {
            return error(STATE_PARAMS_ERROR);
        }
        record = record.parseFromDTO(item);
        flupProjectRecordService.updateById(record);
        String logContent = String.format("确认复诊项目, 复诊项目id: %d", flupProjectId);
        baseCommonService.addLog(logContent, OPERATE_TYPE_UPDATE);
        return Result.OK();
    }

    /**
     * 组装复诊日期对象
     *
     * @param flupDate 复诊日期 yyyy-MM-dd 部分
     * @param flupTime 复诊时间 hh:mm:ss 部分
     * @return 组装后的 datetime 对象
     */
    @SneakyThrows
    private DateTime wrapperDate(String flupDate, Integer flupTime) {
        String startTime = Constant.FlupTime.valueOf(flupTime).getStartTime();
        String dateStr = flupDate + " " + startTime + ":00";
        return DateUtil.parse(dateStr, DateUtils.datetimeFormat.get().toPattern());
    }
}
